App.require(function () {
    var svgNeedObj = {
        m: 2,
        M: 2,
        l: 2,
        L: 2,
        Q: 4,
        q: 4,
        c: 6,
        C: 6,
        h: 1,
        H: 1,
        v: 1,
        V: 1,
        t: 2,
        T: 2,
        s: 4,
        S: 4,
        a: 7,
        A: 7,
        z: 0,
        Z: 0
    };
    var computedSvgObj = {
        M: 2,
        L: 2,
        Q: 4,
        C: 6,
        H: 2,
        V: 2,
        T: 4,
        S: 6,
        A: 7,
        Z: 0
    };
    var colorObj = JSON.parse(`{"black":"#000000","night":"#0C090A","gunmetal":"#2C3539","midnight":"#2B1B17","charcoal":"#34282C","darkslategrey":"#25383C","oil":"#3B3131","blackcat":"#413839","iridium":"#3D3C3A","blackeel":"#463E3F","blackcow":"#4C4646","graywolf":"#504A4B","vampiregray":"#565051","graydolphin":"#5C5858","carbongray":"#625D5D","ashgray":"#666362","cloudygray":"#6D6968","smokeygray":"#726E6D","gray":"#736F6E","granite":"#837E7C","battleshipgray":"#848482","graycloud":"#B6B6B4","graygoose":"#D1D0CE","platinum":"#E5E4E2","metallicsilver":"#BCC6CC","bluegray":"#98AFC7","lightslategray":"#6D7B8D","slategray":"#657383","jetgray":"#616D7E","mistblue":"#646D7E","marbleblue":"#566D7E","slateblue":"#357EC7","steelblue":"#4863A0","bluejay":"#2B547E","darkslateblue":"#2B3856","midnightblue":"#151B54","navyblue":"#000080","bluewhale":"#342D7E","lapisblue":"#15317E","cornflowerblue":"#6495ED","earthblue":"#0000A0","cobaltblue":"#0020C2","blueberryblue":"#0041C2","sapphireblue":"#2554C7","blueeyes":"#1569C7","royalblue":"#2B60DE","blueorchid":"#1F45FC","bluelotus":"#6960EC","lightslateblue":"#736AFF","glacialblueice":"#368BC1","silkblue":"#488AC7","blueivy":"#3090C7","bluekoi":"#659EC7","columbiablue":"#87AFC7","babyblue":"#95B9C7","lightsteelblue":"#728FCE","oceanblue":"#2B65EC","blueribbon":"#306EFF","bluedress":"#157DEC","dodgerblue":"#1589FF","skyblue":"#6698FF","butterflyblue":"#38ACEC","iceberg":"#56A5EC","crystalblue":"#5CB3FF","deepskyblue":"#3BB9FF","denimblue":"#79BAEC","lightskyblue":"#82CAFA","dayskyblue":"#82CAFF","jeansblue":"#A0CFEC","blueangel":"#B7CEEC","pastelblue":"#B4CFEC","seablue":"#C2DFFF","powderblue":"#C6DEFF","coralblue":"#AFDCEC","lightblue":"#ADDFFF","robineggblue":"#BDEDFF","palebluelily":"#CFECEC","lightcyan":"#E0FFFF","water":"#EBF4FA","aliceblue":"#F0F8FF","azure":"#F0FFFF","lightslate":"#CCFFFF","lightaquamarine":"#93FFE8","electricblue":"#9AFEFF","aquamarine":"#7FFFD4","cyanoraqua":"#00FFFF","tronblue":"#7DFDFE","bluezircon":"#57FEFF","bluelagoon":"#8EEBEC","celeste":"#50EBEC","bluediamond":"#4EE2EC","tiffanyblue":"#81D8D0","cyanopaque":"#92C7C7","bluehosta":"#77BFC7","northernlightsblue":"#78C7C7","mediumturquoise":"#48CCCD","turquoise":"#43C6DB","jellyfish":"#46C7C7","macawbluegreen":"#43BFC7","lightseagreen":"#3EA99F","darkturquoise":"#3B9C9C","seaturtlegreen":"#438D80","mediumaquamarine":"#348781","greenishblue":"#307D7E","grayishturquoise":"#5E7D7E","beetlegreen":"#4C787E","teal":"#008080","seagreen":"#4E8975","camouflagegreen":"#78866B","sagegreen":"#848b79","hazelgreen":"#617C58","venomgreen":"#728C00","ferngreen":"#667C26","darkforestgreen":"#254117","mediumseagreen":"#306754","mediumforestgreen":"#347235","seaweedgreen":"#437C17","pinegreen":"#387C44","junglegreen":"#347C2C","shamrockgreen":"#347C17","mediumspringgreen":"#348017","forestgreen":"#4E9258","greenonion":"#6AA121","springgreen":"#4AA02C","limegreen":"#41A317","clovergreen":"#3EA055","greensnake":"#6CBB3C","aliengreen":"#6CC417","greenapple":"#4CC417","yellowgreen":"#52D017","kellygreen":"#4CC552","zombiegreen":"#54C571","froggreen":"#99C68E","greenpeas":"#89C35C","dollarbillgreen":"#85BB65","darkseagreen":"#8BB381","iguanagreen":"#9CB071","avocadogreen":"#B2C248","pistachiogreen":"#9DC209","saladgreen":"#A1C935","hummingbirdgreen":"#7FE817","nebulagreen":"#59E817","stoplightgogreen":"#57E964","algaegreen":"#64E986","jadegreen":"#5EFB6E","green":"#00FF00","emeraldgreen":"#5FFB17","lawngreen":"#87F717","chartreuse":"#8AFB17","dragongreen":"#6AFB92","mintgreen":"#98FF98","greenthumb":"#B5EAAA","lightjade":"#C3FDB8","teagreen":"#CCFB5D","greenyellow":"#B1FB17","slimegreen":"#BCE954","goldenrod":"#EDDA74","harvestgold":"#EDE275","sunyellow":"#FFE87C","yellow":"#FFFF00","cornyellow":"#FFF380","parchment":"#FFFFC2","cream":"#FFFFCC","lemonchiffon":"#FFF8C6","cornsilk":"#FFF8DC","beige":"#F5F5DC","blonde":"#FBF6D9","antiquewhite":"#FAEBD7","champagne":"#F7E7CE","blanchedalmond":"#FFEBCD","vanilla":"#F3E5AB","tanbrown":"#ECE5B6","peach":"#FFE5B4","mustard":"#FFDB58","rubberduckyyellow":"#FFD801","brightgold":"#FDD017","goldenbrown":"#EAC117","macaroniandcheese":"#F2BB66","saffron":"#FBB917","beer":"#FBB117","cantaloupe":"#FFA62F","beeyellow":"#E9AB17","brownsugar":"#E2A76F","burlywood":"#DEB887","deeppeach":"#FFCBA4","gingerbrown":"#C9BE62","schoolbusyellow":"#E8A317","sandybrown":"#EE9A4D","fallleafbrown":"#C8B560","orangegold":"#D4A017","sand":"#C2B280","cookiebrown":"#C7A317","caramel":"#C68E17","brass":"#B5A642","khaki":"#ADA96E","camelbrown":"#C19A6B","bronze":"#CD7F32","tigerorange":"#C88141","cinnamon":"#C58917","bulletshell":"#AF9B60","darkgoldenrod":"#AF7817","copper":"#B87333","wood":"#966F33","oakbrown":"#806517","moccasin":"#827839","armybrown":"#827B60","sandstone":"#786D5F","mocha":"#493D26","taupe":"#483C32","coffee":"#6F4E37","brownbear":"#835C3B","reddirt":"#7F5217","sepia":"#7F462C","orangesalmon":"#C47451","rust":"#C36241","redfox":"#C35817","chocolate":"#C85A17","sedona":"#CC6600","papayaorange":"#E56717","halloweenorange":"#E66C2C","pumpkinorange":"#F87217","constructionconeorange":"#F87431","sunriseorange":"#E67451","mangoorange":"#FF8040","darkorange":"#F88017","coral":"#FF7F50","basketballorange":"#F88158","lightsalmon":"#F9966B","tangerine":"#E78A61","darksalmon":"#E18B6B","lightcoral":"#E77471","beanred":"#F75D59","valentinered":"#E55451","shockingorange":"#E55B3C","red":"#FF0000","scarlet":"#FF2400","rubyred":"#F62217","ferrarired":"#F70D1A","fireenginered":"#F62817","lavared":"#E42217","lovered":"#E41B17","grapefruit":"#DC381F","chestnutred":"#C34A2C","cherryred":"#C24641","mahogany":"#C04000","chillipepper":"#C11B17","cranberry":"#9F000F","redwine":"#990012","burgundy":"#8C001A","chestnut":"#954535","bloodred":"#7E3517","sienna":"#8A4117","sangria":"#7E3817","firebrick":"#800517","maroon":"#810541","plumpie":"#7D0541","velvetmaroon":"#7E354D","plumvelvet":"#7D0552","rosyfinch":"#7F4E52","puce":"#7F5A58","dullpurple":"#7F525D","rosybrown":"#B38481","khakirose":"#C5908E","pinkbow":"#C48189","lipstickpink":"#C48793","rose":"#E8ADAA","desertsand":"#EDC9AF","pigpink":"#FDD7E4","cottoncandy":"#FCDFFF","pinkbubblegum":"#FFDFDD","mistyrose":"#FBBBB9","pink":"#FAAFBE","lightpink":"#FAAFBA","flamingopink":"#F9A7B0","pinkrose":"#E7A1B0","pinkdaisy":"#E799A3","cadillacpink":"#E38AAE","carnationpink":"#C12283","blushred":"#E56E94","hotpink":"#F660AB","watermelonpink":"#FC6C85","violetred":"#F6358A","deeppink":"#F52887","pinkcupcake":"#E45E9D","pinklemonade":"#E4287C","neonpink":"#F535AA","magenta":"#FF00FF","dimorphothecamagenta":"#E3319D","brightneonpink":"#F433FF","palevioletred":"#D16587","tulippink":"#C25A7C","mediumvioletred":"#CA226B","roguepink":"#C12869","burntpink":"#C12267","bashfulpink":"#C25283","plum":"#B93B8F","violapurple":"#7E587E","purpleiris":"#571B7E","plumpurple":"#583759","indigo":"#4B0082","purplemonster":"#461B7E","purplehaze":"#4E387E","eggplant":"#614051","grape":"#5E5A80","purplejam":"#6A287E","darkorchid":"#7D1B7E","purpleflower":"#A74AC7","mediumorchid":"#B048B5","purpleamethyst":"#6C2DC7","darkviolet":"#842DCE","violet":"#8D38C9","purplesagebush":"#7A5DC7","lovelypurple":"#7F38EC","purple":"#8E35EF","aztechpurple":"#893BFF","mediumpurple":"#8467D7","jasminepurple":"#A23BEC","purpledaffodil":"#B041FF","tyrianpurple":"#C45AEC","crocuspurple":"#9172EC","purplemimosa":"#9E7BFF","heliotropepurple":"#D462FF","crimson":"#E238EC","purpledragon":"#C38EC7","lilac":"#C8A2C8","blushpink":"#E6A9EC","mauve":"#E0B0FF","wisteriapurple":"#C6AEC7","blossompink":"#F9B7FF","thistle":"#D2B9D3","periwinkle":"#E9CFEC","lavenderpinocchio":"#EBDDE2","lavenderblue":"#E3E4FA","pearl":"#FDEEF4","seashell":"#FFF5EE","milkwhite":"#FEFCFF","white":"#FFFFFF"}`);
    App.define("canvasTool", {
        defaultKey: {
            linedash: "",
            param: 0,
            linedashoffset: 0,
            linewidth: 1,
            shadow: "0 0 0 rgba(0, 0, 0, 0)",
            stroke: "black",
            transform: "translate(0, 0)",
            offset: "0 0",
            opacity: 1,
            max: Math.PI * 2,
            percent: 1
        },
        getProperty: function (key, target) {
            if (target._animation && target._animation.support.indexOf(key) !== -1) {
                return target._animation.getProperty(key, target);
            }
            switch (key) {
                case "steps":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return target[key] ? parseInt(target[key]) : 0;
                case "font":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return target[key];
                case "transform":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return this.createTransformList(target[key]);
                case "linedash":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return this.createLineDash(target[key]);
                case "shadow":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return this.changeShadowStr(target[key]);
                case "offset":
                case "rstart":
                case "rend":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return this.createOffsetObj(target[key]);
                case "dlength":
                case "percent":
                case "distance":
                case "opacity":
                case "cwidth":
                case "x":
                case "y":
                case "sx":
                case "sy":
                case "sw":
                case "sh":
                case "ir":
                case "or":
                case "linedashoffset":
                case "linewidth":
                case "max":
                case "startoffset":
                case "width":
                case "height":
                case "cwidth":
                case "fheight":
                case "fwidth":
                case "r":
                case "padding":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return parseFloat(target[key]);
                case "fill":
                case "stroke":
                case "fontfill":
                case "activefill":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return target[key];
                case "helpfill":
                case "helpstroke":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return target[key].split(/;\s*/g);
                case "path":
                    if (target._duration && target._duration.current[key]) {
                        return target._duration.current[key];
                    }
                    return {
                        action: target.data.action,
                        points: target.data.points
                    }
                default: 
                    return target[key];
            }
        },
        createFont: function (str) {
            if (str) {
                var pattern = /^(\d+)px\s+([\s\S]+)\s*$/,  match = pattern.exec(str);
                if (match) {
                    return {
                        size: match[1],
                        font: match[2]
                    }
                }
            }
        },
        update: function (obj, elapsed, duration, fn) {
            var passed = fn(elapsed, duration);
            for (var key in obj.current) {
                var value = this.computedHalfByKey(key, {
                    current: obj.current[key],
                    old: obj.old[key],
                    target: obj.target[key]
                }, passed);
                if (typeof value !== "undefined") obj.current[key] = value;
            }
        },
        createDurationObj: function (old, current, elapsed) {
            var result = {},
                _old = {},
                _current = {};
            for (var key in old) {
                var oldList = this._computedToNumber(key, old[key]),
                    newList = this._computedToNumber(key, current[key]);

                result[key] = this.computedHalf(key, oldList, newList, elapsed);
                _old[key] = this.computedHalf(key, oldList, newList, 0);
                _current[key] = this.computedHalf(key, oldList, newList, 1);
            }
            return {
                current: result,
                old: _old,
                target: _current
            }
        },
        computedHalfByKey: function (key, obj, passed) {
            var noPass = 1 - passed,
                current = obj.current,
                old = obj.old,
                target = obj.target;
            switch (key) {
                case "shadow":
                    current.x = parseInt(noPass * old.x + passed * target.x);
                    current.y = parseInt(noPass * old.y + passed * target.y);
                    current.blur = parseInt(noPass * old.blur + passed * target.blur);
                    this.computedHalfByKey("color", {
                        current: current.color,
                        old: old.color,
                        target: target.color
                    }, passed);
                    break;
                case "param":
                case "linedash":
                    for (var i = 0; i < current.length; i++) {
                        current[i] = old[i] * noPass + target[i] * passed;
                    }
                    break;
                case "offset":
                case "rstart":
                case "rend":
                    current.x = parseInt(noPass * old.x + passed * target.x);
                    current.y = parseInt(noPass * old.y + passed * target.y);
                    break;
                case "color":
                    current.r = parseInt(noPass * old.r + passed * target.r);
                    current.g = parseInt(noPass * old.g + passed * target.g);
                    current.b = parseInt(noPass * old.b + passed * target.b);
                    current.a = noPass * old.a + passed * target.a;
                    break;
                case "helpfill":
                case "helpstroke":
                    for (var i = 0; i < current.length; i++) {
                        this.computedHalfByKey("fill", {
                            current: current[i],
                            old: old[i],
                            target: target[i]
                        }, passed)
                    }
                    break;
                case "fill":
                case "stroke":
                    if (typeof current === "string") return;
                    this.computedHalfByKey("color", {
                        current: current,
                        old: old,
                        target: target
                    }, passed);
                    break;
                case "transform":
                    for (var i = 0; i < current.length; i++) {
                        this.computedHalfByKey(current[i].action, {
                            current: current[i].args,
                            old: old[i].args,
                            target: target[i].args
                        }, passed);
                    }
                    break;
                case "translate":
                case "scale":
                    current[0] = old[0] * noPass + target[0] * passed;
                    current[1] = old[1] * noPass + target[1] * passed;
                    break;
                case "rotate":
                    current[0] = old[0] * noPass + target[0] * passed;
                    break;
                case "path":
                    this.computedHalfByKey("pathpoint", {
                        current: current.points,
                        old: old.points,
                        target: target.points
                    }, passed);
                    break;
                case "pathpoint":
                    for (var i = 0; i < current.length; i++) {
                        current[i] = old[i] * noPass + target[i] * passed;
                    }
                    break;
                case "font":
                    if (typeof current === "string") return;
                    current.size = old.size * noPass + target.size * passed;
                    break;
                default: 
                    return old * noPass + target * passed;
            }
        },
        createDefaultPoints: function (points, str) {
            var x = 0,
                y = 0,
                len = points.length;
            if (len > 0) {
                x = points[len - 2];
                y = points[len - 1];
            }
            switch (str) {
                case "L":
                case "H":
                case "V":
                case "M":
                    return [x, y];
                case "Z":
                    return [];
                case "T":
                case "Q":
                    return [x, y, x, y];
                case "C":
                case "S":
                    return [x, y, x, y, x, y];
                case "A":
                    return [0, 0, 0, 0, 0, x, y];
            }
        },
        computedHalf: function (key, oObj, nObj, passed) {
            var noPass = 1 - passed;
            switch (key) {
                case "shadow":
                    return {
                        x: parseInt(noPass * oObj.x + passed * nObj.x),
                        y: parseInt(noPass * oObj.y + passed * nObj.y),
                        blur: parseInt(noPass * oObj.blur + passed * nObj.blur),
                        color: typeof oObj.color === "object" ? {
                            r: parseInt(noPass * oObj.color.r + passed * nObj.color.r),
                            g: parseInt(noPass * oObj.color.g + passed * nObj.color.g),
                            b: parseInt(noPass * oObj.color.b + passed * nObj.color.b),
                            a: parseFloat(noPass * oObj.color.a + passed * nObj.color.a),
                        } : this.revertColorToInt(this.computedHalf("color", this.toColor(oObj.color), this.toColor(nObj.color), passed))
                    };
                case "param":
                case "linedash":
                    var max = Math.max(oObj.length, nObj.length),
                        result = [];
                    for (var i = 0; i < max; i++) {
                        result.push(
                            (oObj[i] ? oObj[i] : 0) * noPass +
                            (nObj[i] ? nObj[i] : 0) * passed
                        );
                    }
                    return result;
                case "offset":
                case "rstart":
                case "rend":
                    return {
                        x: parseFloat(noPass * oObj.x + passed * nObj.x),
                        y: parseFloat(noPass * oObj.y + passed * nObj.y),
                    };
                case "color":
                    return {
                        r: parseInt(noPass * oObj.r + passed * nObj.r),
                            g: parseInt(noPass * oObj.g + passed * nObj.g),
                            b: parseInt(noPass * oObj.b + passed * nObj.b),
                            a: noPass * oObj.a + passed * nObj.a
                    };
                case "helpfill":
                case "helpstroke":
                    var oList = [],
                        nList = [],
                        max = Math.max(oObj.length, nObj.length),
                        that = this;
                    for (var i = 0; i < max; i++) {
                        oList.push(oObj[i % oObj.length]);
                        nList.push(nObj[i % nObj.length]);
                    }
                    return oList.map(function (item, i) {
                        return that.computedHalf("fill", item, nList[i], passed);
                    })
                case "fill":
                case "stroke":
                    if (typeof oObj === "string" || typeof nObj === "string") return nObj;
                    return this.computedHalf("color", oObj, nObj, passed);
                case "transform":
                    var tOObj = [],
                        tNObj = [],
                        nIndex = 0;
                    for (var i = 0; i < oObj.length; i++) {
                        var to = oObj[i];
                        tOObj.push(to);
                        if (nObj[nIndex] && to.action == nObj[nIndex].action) {
                            tNObj.push(nObj[nIndex++])
                        } else {
                            tNObj.push({
                                action: to.action,
                                args: this.defaultTransform(to.action)
                            });
                        }
                    }

                    for (var i = nIndex; i < nObj.length; i++) {
                        tNObj.push(nObj[i]);
                        tOObj.push({
                            action: nObj[i].action,
                            args: this.defaultTransform(nObj[i].action)
                        });
                    }
                    var result = [];
                    for (var i = 0; i < tNObj.length; i++) {
                        result.push({
                            action: tNObj[i].action,
                            args: this.computedHalf(tNObj[i].action, tOObj[i].args, tNObj[i].args, passed)
                        })
                    }
                    return result;
                case "translate":
                case "scale":
                    return [
                        noPass * oObj[0] + passed * nObj[0],
                        noPass * oObj[1] + passed * nObj[1]
                    ];
                case "rotate":
                    return [noPass * oObj[0] + passed * nObj[0]];
                case "path":
                    var prevActions = [],
                        nextActions = [],
                        prevPoints = [],
                        nextPoints = [],
                        nIndex = 0,
                        svgObj = computedSvgObj;
                    var oPoints = oObj.points.slice(),
                        nPoints = nObj.points.slice();

                    if (nObj.action.length > oObj.action.length) {
                        for (var i = 0; i < nObj.action.length; i++) {
                            var to = nObj.action[i];
                            nextPoints.push.apply(nextPoints, nPoints.splice(0, svgObj[to]));
                            nextActions.push(to);
                            if (oObj.action[nIndex] && oObj.action[nIndex] === to) {
                                prevActions.push(oObj.action[nIndex++]);
                                prevPoints.push.apply(prevPoints, oPoints.splice(0, svgObj[to]));
                            } else {
                                prevActions.push(to);
                                prevPoints.push.apply(prevPoints, this.createDefaultPoints(prevPoints, to));
                            }
                        }

                        for (var i = nIndex; i < oObj.action.length; i++) {
                            var to = oObj.action[i];
                            prevActions.push(to);
                            prevPoints.push.apply(prevPoints, oPoints.splice(0, svgObj[to]));
                            nextActions.push(to);
                            nextPoints.push.apply(nextPoints, this.createDefaultPoints(nextPoints, to));
                        }
                    } else {
                        for (var i = 0; i < oObj.action.length; i++) {
                            var to = oObj.action[i];
                            prevPoints.push.apply(prevPoints, oPoints.splice(0, svgObj[to]));
                            prevActions.push(to);
                            if (nObj.action[nIndex] && nObj.action[nIndex] === to) {
                                nextActions.push(nObj.action[nIndex++]);
                                nextPoints.push.apply(nextPoints, nPoints.splice(0, svgObj[to]));
                            } else {
                                nextActions.push(to);
                                nextPoints.push.apply(nextPoints, this.createDefaultPoints(nextPoints, to));
                            }
                        }

                        for (var i = nIndex; i < nObj.action.length; i++) {
                            var to = nObj.action[i];
                            nextActions.push(to);
                            nextPoints.push.apply(nextPoints, nPoints.splice(0, svgObj[to]));
                            prevActions.push(to);
                            prevPoints.push.apply(prevPoints, this.createDefaultPoints(prevPoints, to));
                        }
                    }

                    return {
                        action: prevActions,
                            points: this.computedHalf("pathpoint", prevPoints, nextPoints, passed)
                    };
                case "pathpoint":
                    var result = [];
                    for (var i = 0; i < oObj.length; i++) {
                        result[i] = oObj[i] * noPass + nObj[i] * passed;
                    }
                    return result;
                case "font":
                    if (typeof oObj === "string" || typeof nObj === "string") return nObj;
                    return {
                        font: oObj.font,
                        size: oObj.size * noPass + nObj.size * passed
                    }
                default:
                    return parseFloat(oObj) * noPass + parseFloat(nObj) * passed;
            }
        },
        defaultTransform: function (str) {
            switch (str) {
                case "translate":
                    return [0, 0]
                case "scale":
                    return [1, 1];
                case "rotate":
                    return [0];
            }
        },
        testColor: function (str) {
            if (colorObj[str.toLowerCase()]) return str;
            if (str.indexOf("#") == 0) {
                var num = parseInt(str.slice(1));
                if (num < 256 * 256 * 256 && num > 0) return str;
            }
            if (str.indexOf("rgb") == 0) return str;
            return false;
        },
        toColor: function (colorStr) {
            if (colorStr.indexOf("#") == 0) {
                var num = parseInt(colorStr.slice(1), 16);
                return {
                    r: parseInt(num / 65536),
                    g: parseInt(num / 256) % 256,
                    b: num % 256,
                    a: 1
                }
            } else if (colorStr.indexOf("rgba") == 0) {
                var pattern = /rgba\((\d+),\s*(\d+),\s*(\d+),\s*([0-9\.]+)\s*\)/;
                var match = pattern.exec(colorStr),
                    r = 0,
                    g = 0,
                    b = 0,
                    a = 1;
                if (match) {
                    r = parseInt(match[1]);
                    g = parseInt(match[2]);
                    b = parseInt(match[3]);
                    a = parseFloat(match[4]);
                }
                return {
                    r: r,
                    g: g,
                    b: b,
                    a: a
                }
            } else if (colorStr.indexOf("rgb") == 0) {
                var pattern = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/;
                var match = pattern.exec(colorStr),
                    r = 0,
                    g = 0,
                    b = 0,
                    a = 1;
                if (match) {
                    r = parseInt(match[1]);
                    g = parseInt(match[2]);
                    b = parseInt(match[3]);
                }
                return {
                    r: r,
                    g: g,
                    b: b,
                    a: a
                }
            } else {
                return this.toColor(colorObj[colorStr.toLowerCase()]);
            }
        },
        revertColorToInt: function (obj) {
            return "rgba(" + [obj.r, obj.g, obj.b, obj.a].join(",") + ")";
        },
        _computedToNumber: function (key, str, isCheckTransition) {
            switch (key) {
                case "value":
                case "x":
                case "y":
                case "left":
                case "top":
                case "width":
                case "height":
                case "sx":
                case "sy":
                case "sw":
                case "sh":
                case "r":
                case "dlength":
                case "opacity":
                case "linewidth":
                case "percent":
                case "cwidth":
                case "distance":
                case "or":
                case "ir":
                case "r":
                case "max":
                case "startoffset":
                case "linedashoffset":
                case "hk":
                case "edgelength":
                case "constant":
                case "endmarkeroffset":
                case "startmarkeroffset":
                case "fheight":
                case "fwidth":
                    return parseFloat(str);
                case "param":
                case "linedash":
                    return str.split(/\s+/).map(function (item) {
                        return parseFloat(item);
                    });
                case "shadow":
                    return this.changeShadowStr(str);
                case "transform":
                    return this.createTransformList(str);
                case "offset":
                case "rstart":
                case "rend":
                    return this.createOffsetObj(str);
                case "path":
                    return this.changePath(str);
                case "fill":
                case "stroke":
                    if (this.testColor(str)) return this.toColor(str);
                    return isCheckTransition ? false : str;
                case "font":
                    var obj = this.createFont(str);
                    if (obj) return obj;
                    return isCheckTransition ? false : str;
                case "helpstroke":
                case "helpfill":
                    var that = this;
                    return str.split(/;\s*/g).map(function (item) {
                        return that._computedToNumber("fill", item);
                    });
                default:
                    return isCheckTransition ? false : str;
            }
        },
        createOffsetObj: function (offStr) {
            if (!offStr) return {
                x: 0,
                y: 0
            };
            var strList = offStr.split(/\s+/);
            if (strList.length == 1) {
                var off = parseFloat(strList[0]);
                return {
                    x: off,
                    y: off
                }
            } else {
                return {
                    x: parseFloat(strList[0]),
                    y: parseFloat(strList[1])
                }
            }
        },
        /**
         * 将transformStr转为转换的方法
         * @param {string} str 样式字符串,支持canvas的转换方式
         * translate(10, 10) scale(2, 1) rotate(.707);
         */
        createTransformList: function (str) {
            var pattern = /(translate|rotate|scale)\(([\S\s]*?)\)/g,
                result = [];
            var matches = pattern.exec(str);
            while (matches) {
                var tList = matches[2].split(",").map(function (item) {
                    return parseFloat(item);
                });
                result.push({
                    action: matches[1],
                    args: tList
                });
                matches = pattern.exec(str);
            }
            return result;
        },
        createLineDash: function (str) {
            if (!str) return false;
            return str.split(/\s+/).map(function (item) {
                return parseFloat(item);
            });
        },
        changeShadowStr: function (str) {
            var pattern = /^\s*(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+([\s\S]+?)\s*$/;
            var match = pattern.exec(str);
            if (match) {
                return {
                    x: parseFloat(match[1]),
                    y: parseFloat(match[2]),
                    blur: parseFloat(match[3]),
                    color: this.toColor(match[4])
                }
            }
            return null;
        },
        computedHeight: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-COLUMN-CHART":
                case "STR-LINE-CHART":
                case "STR-LAYER":
                case "STR-SCATTER-CHART":
                case "STR-HEAT-CHART":
                case "STR-RELATIVE-CHART":
                    if (str) return parseInt(str);
                    var parentCanvas = target.getParentView();
                    return parentCanvas.height - target.y;
                case "STR-IMG-LAYER":
                case "STR-RECT-LAYER":
                    return typeof str !== "undefined" ? parseInt(str) : 0;
                default:
                    return typeof str !== "undefined" ? parseInt(str) : 400;
            }
        },
        computedWidth: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-COLUMN-CHART":
                case "STR-LINE-CHART":
                case "STR-LAYER":
                case "STR-SCATTER-CHART":
                case "STR-HEAT-CHART":
                case "STR-RELATIVE-CHART":
                    if (str) return parseInt(str);
                    var parentCanvas = target.getParentView();
                    return parentCanvas.width - target.x;
                case "STR-IMG-LAYER":
                case "STR-RECT-LAYER":
                    return typeof str !== "undefined" ? parseInt(str) : 0;
                default:
                    return typeof str !== "undefined" ? parseInt(str) : 400;
            }
        },
        computedType: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-LINE-CHART":
                    return str || "polyline";
                default:
                    return str || "";
            }
        },
        computedStroke: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-LINE-CHART":
                    return str || "black";
                default:
                    return str || "";
            }
        },
        computedDistance: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-FUNNEL-CHART":
                case "STR-LINE-CHART":
                    return typeof str === "undefined" ? 30 : parseFloat(str);
                case "STR-COLUMN-CHART":
                    return typeof str === "undefined" ? 1.6 * target.cwidth : parseFloat(str);
            }
        },
        computedDirection: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-PIE-CHART":
                    return str || "CW";
                default:
                    return str || "row";
            }
        },
        computedRadial: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-RADAR-CHART":
                    return typeof str === "undefined" ? 100 : parseFloat(str);
                case "STR-HEAT-CHART":
                    return typeof str === "undefined" ? 10 : parseFloat(str);
                default:
                    return typeof str === "undefined" ? 0 : parseFloat(str);
            }
        },
        computedMax: function (target, str) {
            switch (target.tagName.toUpperCase()) {
                case "STR-PIE-CHART":
                    return typeof str === "undefined" ? Math.PI * 2 : parseFloat(str);
                case "STR-HEAT-CHART":
                    return typeof str === "undefined" ? 10 : parseFloat(str);
                default:
                    return typeof str === "undefined" ? 0 : parseFloat(str);
            }
        },
        strToLayerType: function (key, str, target) {
            switch (key) {
                case "x1":
                case "x2":
                case "y1":
                case "y2":
                case "x":
                case "y":
                case "sx":
                case "sy":
                case "sw":
                case "sh":
                case "or":
                case "ir":
                case "sr":
                    return typeof str === "undefined" ? 0 : parseFloat(str);
                case "fx":
                    return typeof str === "undefined" ? target.sx : parseFloat(str);
                case "fy":
                    return typeof str === "undefined" ? target.sy : parseFloat(str);
                case "fr":
                    return typeof str === "undefined" ? target.sr : parseFloat(str);
                case "dlength":
                    return typeof str === "undefined" ? 10 : parseInt(str);
                case "fheight":
                    return typeof str === "undefined" ? target.distance - 5 : parseInt(str);
                case "fwidth":
                    return typeof str === "undefined" ? 100 : parseInt(str);
                case "helpstroke":
                    return str || "rgba(0, 0, 0, .3)";
                case "steps":
                    return typeof str === "undefined" ? 5 : parseInt(str);
                case "r":
                    return this.computedRadial(target, str);
                case "mark":
                case "hidden":
                    return typeof str !== "undefined";
                case "width":
                    return this.computedWidth(target, str);
                case "startoffset":
                    return typeof str === "undefined" ? -Math.PI / 2 : parseFloat(str);
                case "max":
                    return this.computedMax(target, str);
                case "height":
                    return this.computedHeight(target, str);
                case "direction":
                    return this.computedDirection(target, str);
                case "cwidth":
                    return typeof str === "undefined" ? 15 : parseFloat(str);
                case "distance":
                    return this.computedDistance(target, str);
                case "offset":
                    return str || "20 20";
                case "opacity":
                    return str;
                case "percent":
                    return typeof str === "undefined" ? 1 : parseFloat(str);
                case "position":
                    return str || "lefttop";
                case "repeat":
                    return str || "repeat";
                case "id":
                    return str || target.uid;
                case "type":
                    return this.computedType(target, str);
                case "calcposition":
                    return str || "auto"
                case "stroke":
                    return this.computedStroke(target, str);
                default:
                    return str || "";
            }
        },
        keyToCanvas: {
            font: "font",
            fill: "fillStyle",
            stroke: "strokeStyle",
            linedashoffset: "lineDashOffset",
            linecap: "lineCap",
            linejoin: "lineJoin",
            linewidth: "lineWidth",
            mitterlimit: "miterLimit",
            align: "textAlign",
            baseline: "textBaseline"
        },
        patternRepeatList: ["repeat", "no-repeat", "repeat-x", "repeat-y"],
        changePath: function (path) {
            if (this.changePath[path]) return this.changePath[path];
            var valueArray = [];
            var motionAction = [];
            var value = "";
            var currentInt = 0,
                needInt = 0;
            var needObj = svgNeedObj;

            path.split("").forEach(function (c) {
                method(c);
            });
            add();
            valueArray = splitWithMethod(valueArray, motionAction);

            function add() {
                if (value.length > 0) {
                    if (++currentInt > needInt) {
                        currentInt = 1;
                        var prevAction = motionAction[motionAction.length - 1];
                        if (prevAction == "m") prevAction = "l";
                        else if (prevAction == "M") prevAction = "L";
                        motionAction.push(prevAction);
                    }
                    valueArray.push(parseFloat(value));
                    value = "";
                }
            }

            function method(c) {
                switch (c) {
                    case "0":
                    case "1":
                    case "2":
                    case "3":
                    case "4":
                    case "5":
                    case "6":
                    case "7":
                    case "8":
                    case "9":
                    case ".":
                        value += c;
                        break;
                    case "-":
                        add();
                        value = "-";
                        break;
                    case ",":
                    case " ":
                        add();
                        break;
                    case "z":
                    case "Z":
                        motionAction.push("Z");
                        needInt = 0;
                        currentInt = 0;
                        break;
                    case "m":
                    case "M":
                    case "l":
                    case "L":
                    case "Q":
                    case "q":
                    case "c":
                    case "C":
                    case "h":
                    case "H":
                    case "v":
                    case "V":
                    case "t":
                    case "T":
                    case "s":
                    case "S":
                    case "a":
                    case "A":
                        add()
                        motionAction.push(c);
                        needInt = needObj[c];
                        currentInt = 0;
                        break;
                }
            }

            function splitWithMethod(valueArray, motionAction) {
                var preArray = [],
                    tempValueArray = valueArray.slice(),
                    ppreArray = [],
                    totalArray = [];

                for (var i = 0, len = motionAction.length; i < len; i++) {
                    var method = motionAction[i];
                    action(method);
                    motionAction[i] = method.toUpperCase();
                }

                return totalArray;

                function action(method) {
                    var point = [];
                    switch (method) {
                        case "M":
                        case "L":
                            point = tempValueArray.splice(0, 2);
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "m":
                        case "l":
                            point = tempValueArray.splice(0, 2);
                            if (preArray.length != 0) {
                                point = [preArray[0] + point[0], preArray[1] + point[1]]
                            }
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "Q":
                            point = tempValueArray.splice(0, 4);
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "q":
                            point = tempValueArray.splice(0, 4);
                            point = [
                                point[0] + preArray[0], point[1] + preArray[1],
                                point[2] + preArray[0], point[3] + preArray[1]
                            ];
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "C":
                            point = tempValueArray.splice(0, 6);
                            ppreArray = point.slice(2, 4);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "c":
                            point = tempValueArray.splice(0, 6);
                            point = [
                                point[0] + preArray[0], point[1] + preArray[1],
                                point[2] + preArray[0], point[3] + preArray[1],
                                point[4] + preArray[0], point[5] + preArray[1]
                            ];
                            ppreArray = point.slice(2, 4);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "H":
                            point = tempValueArray.splice(0, 1);
                            point = [point[0], preArray[1]];
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "h":
                            point = tempValueArray.splice(0, 1);
                            point = [point[0] + preArray[0], preArray[1]];
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "V":
                            point = tempValueArray.splice(0, 1);
                            point = [preArray[0], point[0]];
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "v":
                            point = tempValueArray.splice(0, 1);
                            point = [preArray[0], point[0] + preArray[1]];
                            preArray = point;
                            totalArray = totalArray.concat(point);
                            break;
                        case "S":
                            var tempPoint = tempValueArray.splice(0, 4);
                            point = [
                                2 * preArray[0] - ppreArray[0],
                                2 * preArray[1] - ppreArray[1],
                                tempPoint[0],
                                tempPoint[1],
                                tempPoint[2],
                                tempPoint[3]
                            ];
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "s":
                            var tempPoint = tempValueArray.splice(0, 4);
                            tempPoint = [
                                tempPoint[0] + preArray[0],
                                tempPoint[1] + preArray[1],
                                tempPoint[2] + preArray[0],
                                tempPoint[3] + preArray[1]
                            ];
                            point = [
                                2 * preArray[0] - ppreArray[0],
                                2 * preArray[1] - ppreArray[1],
                                tempPoint[0],
                                tempPoint[1],
                                tempPoint[2],
                                tempPoint[3]
                            ];
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "T":
                            var tempPoint = tempValueArray.splice(0, 2);
                            point = [2 * preArray[0] - ppreArray[0], 2 * preArray[1] - ppreArray[1],
                                tempPoint[0], tempPoint[1]
                            ];
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "t":
                            var tempPoint = tempValueArray.splice(0, 2);
                            tempPoint = [tempPoint[0] + preArray[0], tempPoint[1] + preArray[1]];
                            point = [2 * preArray[0] - ppreArray[0], 2 * preArray[1] - ppreArray[1],
                                tempPoint[0], tempPoint[1]
                            ];
                            ppreArray = point.slice(0, 2);
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                            break;
                        case "a":
                            var tempPoint = tempValueArray.slice(0, 7);
                            point = [
                                preArray[0], preArray[1], tempPoint[0], tempPoint[1], tempPoint[2],
                                tempPoint[3], tempPoint[4],
                                tempPoint[5] + preArray[0], tempPoint[6] + preArray[1]
                            ];
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                        case "A":
                            var tempPoint = tempValueArray.slice(0, 7);
                            point = [
                                preArray[0], preArray[1], tempPoint[0], tempPoint[1], tempPoint[2],
                                tempPoint[3], tempPoint[4], tempPoint[5], tempPoint[6]
                            ];
                            preArray = point.slice(-2);
                            totalArray = totalArray.concat(point);
                        case "Z":
                            break;
                    }
                }
            }

            var obj = {
                action: motionAction,
                points: valueArray
            }

            this.changePath[path] = obj;

            return obj;
        }
    });
})